#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include <fcntl.h>

#include <openssl/md5.h>

#include "kylin-activation.h"
#include "misc.h"


#define BUF_SIZE 4096
#define LINE_SIZE 512
#define CMDLINE_SIZE 256

#define PACKAGE_KEY "kord"

typedef struct kv
{
	char* key;
	char* value;
}kv_t;

kv_t file_in_package[] = {
//	{"/bin/bash", "bash"},
//	{"/usr/bin/kylin-verify", "kylin-verify"},
//	{"/usr/bin/kylin-verify-gui", "kylin-verify"},
	{"/usr/bin/kylin_activation_check", "libkylin-activation"},
};

/*
kv_t file_with_md5sum[] = {
//	{"/etc/update-motd.d/99-kylin-verify-info", "e7719ea5f98b895fa407bae34850354c"},
//	{"/etc/xdg/autostart/kylin-notification.desktop", "e0a6c10ef2f670235b4009ae24450d1a"},
};
*/

/*
kv_t packages[] = 
{
	{"bash", "kord"},
	{"kylin-verify", "kord"},
};
*/

#ifdef CHECK_ENV
#ifdef DEB_PACKAGE

/*
 * _find_md5sum_for_file, check if a md5sum of a file can be find in a package infomation
 * file_path: file path
 * package_name: package name
 * return 1 if found, or 0 if not
 */
static int _find_md5sum_for_file(const char* file_path, char* buf, const char* package_name)
{
	FILE* f = NULL;
	char line[LINE_SIZE];
	char pkg_info_file[LINE_SIZE];
	char* s = NULL;
	char* str = NULL;
	int ret = 0;


	memset(pkg_info_file, 0, LINE_SIZE);
	sprintf(pkg_info_file, "/var/lib/dpkg/info/%s.md5sums", package_name);

	f = fopen(pkg_info_file, "r");

	if(NULL == f)
		return 0;

	while(NULL != (s = fgets(line, LINE_SIZE, f)))
	{
		if(NULL != (str = strstr(line, file_path + 1)))
		{
			if(0 == strncmp(str, file_path + 1, strlen(str) - 1))
			{
				memcpy(buf, line, 2 * MD5_DIGEST_LENGTH);
				ret = 1;
			}
		}
	}
	
	fclose(f);
	return ret;
}

/*
 * _check_file_md5, check if a md5sum of a file matches
 * file_path: file path
 * md5sum: md5sum
 * return 1 if matches, or 0 if not
 */
static int _check_file_md5(const char* file_path, const char* md5sum)
{
	unsigned char md[MD5_DIGEST_LENGTH];
	char digest_str[2 * MD5_DIGEST_LENGTH];
	unsigned char buf[BUF_SIZE];
	int i = 0;
	int fd = -1;
	int ret = 0;
	MD5_CTX ctx;
	int bytes = -1;


	if(strlen(md5sum) != (2 * MD5_DIGEST_LENGTH))
		return 0;

	fd = open(file_path, O_RDONLY);
	if(fd < 0)
		return 0;

	MD5_Init(&ctx);
	while((bytes = read(fd, buf, BUF_SIZE)) > 0)
		MD5_Update(&ctx, buf, bytes);
	MD5_Final(md, &ctx);

	if(bytes < 0)
		goto check_file_out;

	for(i = 0; i < MD5_DIGEST_LENGTH; i++)
		sprintf(&digest_str[2 * i], "%02x", md[i] & 0xff);

	for(i = 0; i < sizeof(digest_str); i++)
	{
		if(isupper(digest_str[i]))
			digest_str[i] = tolower(digest_str[i]);
	}

	if(0 == strncmp(digest_str, md5sum, 2 * MD5_DIGEST_LENGTH))
		ret = 1;

check_file_out:

	close(fd);
	return ret;
}

/*
 * check_file_md5_in_package, check if a file's md5sum matches the md5sum found in package information
 * file_path: file path
 * package_name: package name
 * return 1 if ok, or 0 if not
 */
static int check_file_md5_in_package(const char* file_path, const char* package_name)
{
	int ret = 0;
    char* result = NULL;
//	char buf[2 * MD5_DIGEST_LENGTH + 1];
        char *buf=(char*)malloc(sizeof(char)*(2 * MD5_DIGEST_LENGTH + 1));
	char resolved_path[BUF_SIZE];

	memset(buf, 0, 2 * MD5_DIGEST_LENGTH + 1);


	result = realpath(file_path, resolved_path);
    (void) result;

	ret = _find_md5sum_for_file(resolved_path, buf, package_name);
	if(0 == ret)
		return ret;

	ret = _check_file_md5(resolved_path, buf);
        free(buf);
	return ret;
}

/*
 * pkg_version_match, check if a package information matches key value
 * return 1 if matches, or 0 if not
 */
/*
static int pkg_version_match(const char* pkg_name, const char* key_value)
{
	FILE *fp = NULL;
	char buffer[BUF_SIZE];
	char cmdline[CMDLINE_SIZE];
	char* p = NULL;
	int result = 0;

	if(!pkg_name || !key_value)
		return 0;

	memset(buffer, 0, BUF_SIZE);
	memset(cmdline, 0, CMDLINE_SIZE);
	sprintf(cmdline, "/usr/bin/dpkg-query -W --showformat='${Version}\n' %s 2>/dev/null", pkg_name);

	fp = popen(cmdline, "r");
	if(!fp)
		return 0;

	p = fgets(buffer, BUF_SIZE, fp);
	if(!p)
	{
		pclose(fp);
		return 0;
	}

	if(strstr(buffer, key_value))
		result = 1;

	pclose(fp);
	return result;
}
*/


/*
 * kylin_env_check, check kylin environment
 * return NO_ERROR if ok, or error number if not
 */
int kylin_env_check(char* buffer)
{
	int i = 0;
	int ret = 0;

/*
	for(i = 0; i < (sizeof(packages) / sizeof(kv_t)); i++)
	{
		ret = pkg_version_match(packages[i].key, packages[i].value);
		if(!ret)
		{
			sprintf(buffer, "%s", packages[i].key);
			return NON_KYLIN_PACKAGE;
		}
	}
*/

	char buf[256]={0};
	FILE *fp=fopen("/etc/.kyinfo", "r");
	if(NULL!=fp)
	{
		while (NULL!=fgets(buf,256,fp))
		{
			if(strlen(buf)>4)
			{
				if(0==strncmp(buf,"name",4))
				{
					if(NULL!=strstr(buf,"Kylin-Desktop"))
					{
						ret=0;
						break;
					}
					else if(NULL!=strstr(buf,"Kylin-Server"))
					{
						ret=1;
						break;
					}
					else
					{
						ret=-1;
						break;
					}
					
				}
			}
		}
		fclose(fp);
	}
	if(ret==0)
	{
		for(i = 0; i < (sizeof(file_in_package) / sizeof(kv_t)); i++)
		{
			ret = check_file_md5_in_package(file_in_package[i].key, file_in_package[i].value);
			if(!ret)
			{
				sprintf(buffer, "%s", file_in_package[i].key);
				return MODIFIED_FILE_ERROR;
			}
		}
	}


/*
	for(i = 0; i < (sizeof(file_with_md5sum) / sizeof(kv_t)); i++)
	{
		ret = file_check_md5(file_with_md5sum[i].key, file_with_md5sum[i].value);
		if(!ret)
		{
			sprintf(buffer, "%s", file_with_md5sum[i].key);
			return MODIFIED_FILE_ERROR;
		}
	}
*/

	return NO_ERROR;
}

#endif
#endif

#if 0

int main(int argc, char** argv)
{
	int result = 0;
	char buffer[BUF_SIZE];

	memset(buffer, 0, BUF_SIZE);

	result = kylin_env_check(buffer);

	printf("%d\n", result);

	return result;
}

#endif

